from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_jwt_extended import JWTManager
from flask_json import FlaskJSON
from flask_caching import Cache
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

from app.common.settings import BASE_DIR
from app.common.json_encoder import JSONEncoder

# orm 框架
db = SQLAlchemy()
# 数据库迁移同步插件
migrate = Migrate()
# jwt插件
jwt = JWTManager()
# 返回json
json = FlaskJSON()
# 缓存
cache = Cache()
# 限流器
limiter = Limiter(key_func=get_remote_address)
# 全局异常处理
from app.error.handler_global_exception import HandlerGlobalException

handler_global_exception = HandlerGlobalException()

# 全局ip过滤
from app.common.app_ip_filter import AppIpFilter

app_ip_filter = AppIpFilter()

# 加载ip解析文件缓存
from pathlib import Path
from app.common.ip_xdb_searcher import XdbSearcher

# 预先加载整个 xdb
ip2region_db_path = Path(__file__).resolve().parent.parent / "data/ip2region.xdb"
ip2region_cb = XdbSearcher.loadContentFromFile(dbfile=ip2region_db_path)


# 插件注册
def init_plugin(app_instance):
    # ORM框架初始化数据库
    db.init_app(app_instance)
    migrate.init_app(app_instance, db)
    jwt.init_app(app_instance)
    json.init_app(app_instance)
    cache.init_app(app_instance)
    limiter.init_app(app_instance)
    app_ip_filter.init_app(app_instance, cache)
    handler_global_exception.init_app(app_instance, json)


# 路由注册
def register_route(app_instance):
    # 博客路由
    from app.blog import register_blog_controller
    register_blog_controller(app_instance)
    # 用户路由
    from app.auth import register_auth_controller
    register_auth_controller(app_instance)
    # 管理用户
    from app.admin import register_admin_controller
    register_admin_controller(app_instance)


# 创建一个全局唯一的Flask
def create_app(test_config=None):
    app = Flask(__name__, instance_relative_config=True)
    with app.app_context():
        # 重写序列化自定义对象的方法
        app.json_encoder = JSONEncoder
        # 加载配置文件
        if test_config is None:
            CONFIG_PATH = BASE_DIR / 'app/common/settings.py'
            app.config.from_pyfile(CONFIG_PATH, silent=True)
        else:
            app.config.from_mapping(test_config)
        # 插件注册
        init_plugin(app)
        # 路由注册
        register_route(app)

    return app
